1 using System;
2 using System.Collections.Generic;
3 using UnityEngine;
4
5 namespace ProceduralToolkit
6 {
7 /// <summary>
8 /// Helper class for procedural mesh generation
9 /// </summary>
10 [Serializable]
11 public partial class MeshDraft
12 {
13 public string name = "";
14 public List<Vector3> vertices = new List<Vector3>();
15 public List<int> triangles = new List<int>();
16 public List<Vector3> normals = new List<Vector3>();
17 public List<Vector4> tangents = new List<Vector4>();
18 public List<Vector2> uv = new List<Vector2>();
19 public List<Vector2> uv2 = new List<Vector2>();
20 public List<Vector2> uv3 = new List<Vector2>();
21 public List<Vector2> uv4 = new List<Vector2>();
22 public List<Color> colors = new List<Color>();
23
24 /// <summary>
25 /// Shortcut for vertices.Count
26 /// </summary>
27 public int vertexCount { get { return vertices.Count; } }
28
29 /// <summary>
30 /// Creates an empty MeshDraft
31 /// </summary>
32 public MeshDraft()
33 {
34 }
35
36 /// <summary>
37 /// Creates new MeshDraft with vertex data from <paramref name="mesh"/>>
38 /// </summary>
39 public MeshDraft(Mesh mesh)
40 {
41 if (mesh == null)
42 {
43 throw new ArgumentNullException("mesh");
44 }
45 name = mesh.name;
46 #if UNITY_5_6_OR_NEWER
47 mesh.GetVertices(vertices);
48 mesh.GetTriangles(triangles, 0);
49 mesh.GetNormals(normals);
50 mesh.GetTangents(tangents);
51 mesh.GetUVs(0, uv);
52 mesh.GetUVs(1, uv2);
53 mesh.GetUVs(2, uv3);
54 mesh.GetUVs(3, uv4);
55 mesh.GetColors(colors);
56 #else
57 vertices.AddRange(mesh.vertices);
58 triangles.AddRange(mesh.triangles);
59 normals.AddRange(mesh.normals);
60 tangents.AddRange(mesh.tangents);
61 uv.AddRange(mesh.uv);
62 uv2.AddRange(mesh.uv2);
63 uv3.AddRange(mesh.uv3);
64 uv4.AddRange(mesh.uv4);
65 colors.AddRange(mesh.colors);
66 #endif
67 }
68
69 /// <summary>
70 /// Adds vertex data from <paramref name="draft"/>
71 /// </summary>
72 public void Add(MeshDraft draft)
73 {
74 if (draft == null)
75 {
76 throw new ArgumentNullException("draft");
77 }
78 foreach (var triangle in draft.triangles)
79 {
80 triangles.Add(triangle + vertices.Count);
81 }
82 vertices.AddRange(draft.vertices);
83 normals.AddRange(draft.normals);
84 tangents.AddRange(draft.tangents);
85 uv.AddRange(draft.uv);
86 uv2.AddRange(draft.uv2);
87 uv3.AddRange(draft.uv3);
88 uv4.AddRange(draft.uv4);
89 colors.AddRange(draft.colors);
90 }
91
92 /// <summary>
93 /// Clears all vertex data and all triangle indices
94 /// </summary>
95 public void Clear()
96 {
97 vertices.Clear();
98 triangles.Clear();
99 normals.Clear();
100 tangents.Clear();
101 uv.Clear();
102 uv2.Clear();
103 uv3.Clear();
104 uv4.Clear();
105 colors.Clear();
106 }
107
108 /// <summary>
109 /// Moves draft vertices by <paramref name="vector"/>
110 /// </summary>
111 public void Move(Vector3 vector)
112 {
113 for (int i = 0; i < vertices.Count; i++)
114 {
115 vertices[i] += vector;
116 }
117 }
118
119 /// <summary>
120 /// Rotates draft vertices by <paramref name="rotation"/>
121 /// </summary>
122 public void Rotate(Quaternion rotation)
123 {
124 for (int i = 0; i < vertices.Count; i++)
125 {
126 vertices[i] = rotation*vertices[i];
127 normals[i] = rotation*normals[i];
128 }
129 }
130
131 /// <summary>
132 /// Scales draft vertices uniformly by <paramref name="scale"/>
133 /// </summary>
134 public void Scale(float scale)
135 {
136 for (int i = 0; i < vertices.Count; i++)
137 {
138 vertices[i] *= scale;
139 }
140 }
141
142 /// <summary>
143 /// Scales draft vertices non-uniformly by <paramref name="scale"/>
144 /// </summary>
145 public void Scale(Vector3 scale)
146 {
147 for (int i = 0; i < vertices.Count; i++)
148 {
149 vertices[i] = Vector3.Scale(vertices[i], scale);
150 normals[i] = Vector3.Scale(normals[i], scale).normalized;
151 }
152 }
153
154 /// <summary>
155 /// Paints draft vertices with <paramref name="color"/>
156 /// </summary>
157 public void Paint(Color color)
158 {
159 colors.Clear();
160 for (int i = 0; i < vertices.Count; i++)
161 {
162 colors.Add(color);
163 }
164 }
165
166 /// <summary>
167 /// Flips draft faces
168 /// </summary>
169 public void FlipFaces()
170 {
171 FlipTriangles();
172 FlipNormals();
173 }
174
175 /// <summary>
176 /// Reverses winding order of draft triangles
177 /// </summary>
178 public void FlipTriangles()
179 {
180 for (int i = 0; i < triangles.Count; i += 3)
181 {
182 var temp = triangles[i];
183 triangles[i] = triangles[i + 1];
184 triangles[i + 1] = temp;
185 }
186 }
187
188 /// <summary>
189 /// Reverses direction of draft normals
190 /// </summary>
191 public void FlipNormals()
192 {
193 for (int i = 0; i < normals.Count; i++)
194 {
195 normals[i] = -normals[i];
196 }
197 }
198
199 /// <summary>
200 /// Flips UV map horizontally in selected <paramref name="channel"/>
201 /// </summary>
202 public void FlipUVHorizontally(int channel = 0)
203 {
204 List<Vector2> list;
205 switch (channel)
206 {
207 case 0:
208 list = uv;
209 break;
210 case 1:
211 list = uv2;
212 break;
213 case 2:
214 list = uv3;
215 break;
216 case 3:
217 list = uv4;
218 break;
219 default:
220 throw new ArgumentOutOfRangeException("channel");
221 }
222 for (var i = 0; i < list.Count; i++)
223 {
224 list[i] = new Vector2(1 - list[i].x, list[i].y);
225 }
226 }
227
228 /// <summary>
229 /// Flips UV map vertically in selected <paramref name="channel"/>
230 /// </summary>
231 public void FlipUVVertically(int channel = 0)
232 {
233 List<Vector2> list;
234 switch (channel)
235 {
236 case 0:
237 list = uv;
238 break;
239 case 1:
240 list = uv2;
241 break;
242 case 2:
243 list = uv3;
244 break;
245 case 3:
246 list = uv4;
247 break;
248 default:
249 throw new ArgumentOutOfRangeException("channel");
250 }
251 for (var i = 0; i < list.Count; i++)
252 {
253 list[i] = new Vector2(list[i].x, 1 - list[i].y);
254 }
255 }
256
257 /// <summary>
258 /// Projects vertices on a sphere with given <paramref name="radius"/> and <paramref name="center"/>, recalculates normals
259 /// </summary>
260 public void Spherify(float radius, Vector3 center = default(Vector3))
261 {
262 for (var i = 0; i < vertices.Count; i++)
263 {
264 normals[i] = (vertices[i] - center).normalized;
265 vertices[i] = normals[i]*radius;
266 }
267 }
268
269 /// <summary>
270 /// Creates new mesh from information in draft
271 /// </summary>
272 public Mesh ToMesh()
273 {
274 var mesh = new Mesh {name = name};
275 mesh.SetVertices(vertices);
276 mesh.SetTriangles(triangles, 0);
277 mesh.SetNormals(normals);
278 mesh.SetTangents(tangents);
279 mesh.SetUVs(0, uv);
280 mesh.SetUVs(1, uv2);
281 mesh.SetUVs(2, uv3);
282 mesh.SetUVs(3, uv4);
283 mesh.SetColors(colors);
284 return mesh;
285 }
286
287 /// <summary>
288 /// Fills <paramref name="mesh"/> with information in draft
289 /// </summary>
290 public void ToMesh(ref Mesh mesh)
291 {
292 if (mesh == null)
293 {
294 throw new ArgumentNullException("mesh");
295 }
296 mesh.Clear(false);
297 mesh.name = name;
298 mesh.SetVertices(vertices);
299 mesh.SetTriangles(triangles, 0);
300 mesh.SetNormals(normals);
301 mesh.SetTangents(tangents);
302 mesh.SetUVs(0, uv);
303 mesh.SetUVs(1, uv2);
304 mesh.SetUVs(2, uv3);
305 mesh.SetUVs(3, uv4);
306 mesh.SetColors(colors);
307 }
308 }
309 }